package ejb.contentManagement;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.io.IOUtils;

import ejb.dto.HotelAvailabilityDTO;
import ejb.dto.HotelDTO;
import entities.Hotel;
import entities.HotelAvailability;
import entities.Location;


@Stateless
public class HotelBean implements HotelMgr {
	
	@PersistenceContext
    private EntityManager em;
	
	/**
	 * Retrieve entity Hotel from the associated Id
	 * @param id
	 * @return entity Hotel associated to the <code>id</code>
	 */
	public Hotel getHotel(int id) {
		return em.find(Hotel.class, id);
	}
	
	/**
	 * Retrieve all Hotel entities
	 * @return all Hotel entities
	 */
	public List<Hotel> getAllHotels() {
    	return em.createNamedQuery("Hotel.findAll", Hotel.class)
                .getResultList();
    }
	
	/**
	 * Retrieve entity Hotel from the associated Id and convert it to corresponding HotelDTO
	 */
	@Override
	public HotelDTO getHotelDTO(int id) {
		return  convertToDTO(getHotel(id));
    }
	
	/**
	 * Retrieve all Hotel entities and convert them into corresponding list of HotelDTO
	 */
	@Override
	public List<HotelDTO> getAllHotelsDTO() {
		List<Hotel> list = getAllHotels();
		List<HotelDTO> newList = new ArrayList<HotelDTO>();
		for(Hotel obj : list) {
			newList.add(convertToDTO(obj));
		}
		return newList;
	}
	
	/**
	 * Retrieve all Hotel entities associated to one Location, and convert them
	 * into corresponding list of HotelDTO
	 */
	@Override
	public List<HotelDTO> getAllHotelsByLocation(int locationId){
		List<Hotel> list = em.createNamedQuery("Hotel.findByLocation", Hotel.class).setParameter("l", em.find(Location.class,  locationId)).getResultList();
		List<HotelDTO> newList = new ArrayList<HotelDTO>();
		for(Hotel obj : list) {
			newList.add(convertToDTO(obj));
		}
		return newList;
	}
	
	/**
	 * Convert entity Hotel (parameter <code>h</code>) into corresponding HotelDTO 
	 * @param h
	 * @return converted HotelDTO
	 */
	public static HotelDTO convertToDTO(Hotel h) {
		if(h == null) {
			return null;
		}
		HotelDTO dto = new HotelDTO();
		
		List<HotelAvailabilityDTO> av = new ArrayList<HotelAvailabilityDTO>();
		
		for(HotelAvailability a : h.getHotelAvailabilities()) {
			av.add(HotelAvailabilityBean.convertToDTO(a));
		}
		
		dto.setId(h.getId());
		dto.setName(h.getName());
		dto.setAddress(h.getAddress());
		dto.setDescription(h.getDescription());
		dto.setLocation(LocationBean.convertToDTO(h.getLocation()));
		dto.setHotelAvailabilities(av);	
		return dto;
	}
	
	/**
	 * Retrieve entity Hotel from the associated Id and delete the corresponding element from the database
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public boolean deleteHotel(int id) {
		try{
			em.remove(em.find(Hotel.class, id));
			em.flush();
		}
		//Catch exceptions in the delete operation from database
		catch(Exception e){
			return false;
		}
		return true;
	}
	
	/**
	 * Create entity Hotel from corresponding HotelDTO and update corresponding element in database
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public boolean updateHotel(HotelDTO updatedHotel) {
		if(updatedHotel.getName().equals("") || 
			updatedHotel.getName().startsWith(" ") ||
			updatedHotel.getName() == null)
			return false;
		try{
			em.merge(new Hotel(updatedHotel, em.find(Location.class, updatedHotel.getLocationId())));
			em.flush();
		}
		//Catch exceptions in update operation of database
		catch(Exception e){
			return false;
		}
		return true;
	}
	
	/**
	 * Create entity Hotel from corresponding HotelDTO and insert new corresponding element in database
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public boolean insertHotel(HotelDTO newHotel) {
		if(newHotel.getName().equals("") ||
			newHotel.getImage() == null || 
			newHotel.getName().startsWith(" ") ||
			newHotel.getName() == null)
			return false;
		Hotel nh = new Hotel(newHotel, em.find(Location.class, newHotel.getLocationId()));
		try{
			em.persist(nh);
			em.flush();
		}
		//Catch exceptions in the insert operation in database
		catch(Exception e){
			return false;
		}
		try {
			InputStream input = newHotel.getImage().getInputstream();
			File dest = new File("../eclipseApps/TravelDreamEAR/TravelDreamWeb_war/images/hotels/" + nh.getId() + ".jpg");
			OutputStream output = new FileOutputStream(dest);
			IOUtils.copy(input, output);
			IOUtils.closeQuietly(output);
		    IOUtils.closeQuietly(input);
		}
		//Catch exceptions in the image uploading operation
		catch(Exception e) {
			e.printStackTrace();
		}
		return true;
	}
		
	
	
}
